// Camera.cpp: implementation of the Camera class.
//
//////////////////////////////////////////////////////////////////////

#include "Camera.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

Camera::Camera()
{
/* Set up the viewing parameters */

  ssgSetFOV     ( HORIZONTAL_FOV, VERTICAL_FOV ) ;
  ssgSetNearFar ( CAMERA_NEAR, CAMERA_FAR ) ; /* nb. skydome is scalable ... so far can be reduced */

// Initialize the position (compared to the airplane one!)
this->cameraPosition.xyz[COORD_X]		=   CAMERA_START_POSITION_X;
this->cameraPosition.xyz[COORD_Y]		=   CAMERA_START_POSITION_Y;
this->cameraPosition.xyz[COORD_Z]		=   CAMERA_START_POSITION_Z;
this->cameraPosition.hpr[HEADING]	    =   CAMERA_START_POSITION_H;
this->cameraPosition.hpr[PITCH]		    =   CAMERA_START_POSITION_P;
this->cameraPosition.hpr[ROLL]			=   CAMERA_START_POSITION_R;

this->moviePosition.xyz[COORD_X]		=   0.0f;
this->moviePosition.xyz[COORD_Y]		=   0.0f;
this->moviePosition.xyz[COORD_Z]		=   0.0f;
this->moviePosition.hpr[HEADING]	    =   0.0f;
this->moviePosition.hpr[PITCH]		    =   0.0f;
this->moviePosition.hpr[ROLL]			=   0.0f;

this->cameraDistance = CAMERA_DISTANCE_RADIUS;

inner_state = FREE_MOVE;

ssgSetCamera(&cameraPosition);
}

Camera::~Camera()
{

}

sgCoord* Camera::getCameraPosition()
{
	return &cameraPosition;
}

sgCoord* Camera::getMoviePosition()
{
	return &moviePosition;
}

void Camera::setCameraPosition(sgCoord new_position)
{
	sgCopyCoord(&(this->cameraPosition),&(new_position));
	ssgSetCamera(&cameraPosition);
}

void Camera::setMoviePosition(sgCoord new_position)
{
	this->moviePosition.xyz[0] = new_position.xyz[0];
	this->moviePosition.xyz[1] = new_position.xyz[1];
	this->moviePosition.xyz[2] = new_position.xyz[2];
	this->moviePosition.hpr[0] = new_position.hpr[0];
	this->moviePosition.hpr[1] = new_position.hpr[1];	
	this->moviePosition.hpr[2] = new_position.hpr[2];
	//printf("Camera Movie Position: %.02f %.02f %.02f %.02f %.02f %.02f\n",moviePosition.xyz[SG_X],moviePosition.xyz[SG_Y],moviePosition.xyz[SG_Z],moviePosition.hpr[0],moviePosition.hpr[1],moviePosition.hpr[2]);
}

void Camera::setFilmPosition(sgCoord* new_position)
{
	ssgSetCamera(new_position);
}

void Camera::move(int mov, float hot)
{
if(inner_state == FREE_MOVE)
	{
	freeMove(mov,hot);
	}
else if(inner_state == MOVIE_MOVE)
	{
	movieMove(mov,hot);
	}
}

void Camera::freeMove(int mov, float hot)
{
switch(mov)
		{
		case PITCH_UP:
				this->cameraPosition.hpr[PITCH] -= CAMERA_ROT_INCREMENT;
				this->cameraPosition.xyz[SG_X]		= this->cameraDistance * (float)sin(this->cameraPosition.hpr[HEADING] * SG_DEGREES_TO_RADIANS) * (float)cos(-this->cameraPosition.hpr[PITCH] * SG_DEGREES_TO_RADIANS);
				this->cameraPosition.xyz[SG_Y]		= this->cameraDistance * -(float)cos(-this->cameraPosition.hpr[PITCH] * SG_DEGREES_TO_RADIANS) * (float)cos(-this->cameraPosition.hpr[HEADING] * SG_DEGREES_TO_RADIANS);
				this->cameraPosition.xyz[SG_Z]		= this->cameraDistance * (float)sin(-this->cameraPosition.hpr[PITCH] * SG_DEGREES_TO_RADIANS);
		break;
		case PITCH_DOWN:
				this->cameraPosition.hpr[PITCH] += CAMERA_ROT_INCREMENT;
				this->cameraPosition.xyz[SG_X]		= this->cameraDistance * (float)sin(this->cameraPosition.hpr[HEADING] * SG_DEGREES_TO_RADIANS) * (float)cos(-this->cameraPosition.hpr[PITCH] * SG_DEGREES_TO_RADIANS);
				this->cameraPosition.xyz[SG_Y]		= this->cameraDistance * -(float)cos(-this->cameraPosition.hpr[PITCH] * SG_DEGREES_TO_RADIANS) * (float)cos(-this->cameraPosition.hpr[HEADING] * SG_DEGREES_TO_RADIANS);
				this->cameraPosition.xyz[SG_Z]		= this->cameraDistance * (float)sin(-this->cameraPosition.hpr[PITCH] * SG_DEGREES_TO_RADIANS);
		break;
		case ROTATE_LEFT:
				this->cameraPosition.hpr[HEADING]  -= CAMERA_ROT_INCREMENT;
				this->cameraPosition.xyz[SG_X]		= this->cameraDistance * (float)sin(this->cameraPosition.hpr[HEADING] * SG_DEGREES_TO_RADIANS) * (float)cos(-this->cameraPosition.hpr[PITCH] * SG_DEGREES_TO_RADIANS);
				this->cameraPosition.xyz[SG_Y]		= this->cameraDistance * -(float)cos(this->cameraPosition.hpr[HEADING] * SG_DEGREES_TO_RADIANS) * (float)cos(-this->cameraPosition.hpr[PITCH] * SG_DEGREES_TO_RADIANS);
		break;
		case ROTATE_RIGHT:
				this->cameraPosition.hpr[HEADING]  += CAMERA_ROT_INCREMENT;
				this->cameraPosition.xyz[SG_X]		= this->cameraDistance * (float)sin(this->cameraPosition.hpr[HEADING] * SG_DEGREES_TO_RADIANS) * (float)cos(-this->cameraPosition.hpr[PITCH] * SG_DEGREES_TO_RADIANS);
				this->cameraPosition.xyz[SG_Y]		= this->cameraDistance * -(float)cos(this->cameraPosition.hpr[HEADING] * SG_DEGREES_TO_RADIANS) *(float)cos(-this->cameraPosition.hpr[PITCH] * SG_DEGREES_TO_RADIANS);
		break;
		case ZOOM_OUT:
				this->cameraDistance += CAMERA_DISTANCE_INCREMENT;
				if(this->cameraDistance > CAMERA_MAX_DISTANCE) this->cameraDistance = CAMERA_MAX_DISTANCE;
				this->cameraPosition.xyz[SG_X]		= this->cameraDistance * (float)sin(this->cameraPosition.hpr[HEADING] * SG_DEGREES_TO_RADIANS) * (float)cos(-this->cameraPosition.hpr[PITCH] * SG_DEGREES_TO_RADIANS);
				this->cameraPosition.xyz[SG_Y]		= this->cameraDistance * -(float)cos(-this->cameraPosition.hpr[PITCH] * SG_DEGREES_TO_RADIANS) * (float)cos(-this->cameraPosition.hpr[HEADING] * SG_DEGREES_TO_RADIANS);
				this->cameraPosition.xyz[SG_Z]		= this->cameraDistance * (float)sin(-this->cameraPosition.hpr[PITCH] * SG_DEGREES_TO_RADIANS);
		break;
		case ZOOM_IN:
				this->cameraDistance -= CAMERA_DISTANCE_INCREMENT;
				if(this->cameraDistance < CAMERA_MIN_DISTANCE) this->cameraDistance = CAMERA_MIN_DISTANCE;
				this->cameraPosition.xyz[SG_X]		= this->cameraDistance * (float)sin(this->cameraPosition.hpr[HEADING] * SG_DEGREES_TO_RADIANS) * (float)cos(-this->cameraPosition.hpr[PITCH] * SG_DEGREES_TO_RADIANS);
				this->cameraPosition.xyz[SG_Y]		= this->cameraDistance * -(float)cos(-this->cameraPosition.hpr[PITCH] * SG_DEGREES_TO_RADIANS) * (float)cos(-this->cameraPosition.hpr[HEADING] * SG_DEGREES_TO_RADIANS);
				this->cameraPosition.xyz[SG_Z]		= this->cameraDistance * (float)sin(-this->cameraPosition.hpr[PITCH] * SG_DEGREES_TO_RADIANS);
		break;
		case TURN_LEFT:
				this->cameraPosition.hpr[HEADING]  += CAMERA_ROT_INCREMENT;
		break;
		case TURN_RIGHT:
				this->cameraPosition.hpr[HEADING]  -= CAMERA_ROT_INCREMENT;
		break;
		case LOOK_UP:
				this->cameraPosition.hpr[PITCH]  += CAMERA_ROT_INCREMENT;
		break;
		case LOOK_DOWN:
				this->cameraPosition.hpr[PITCH]  -= CAMERA_ROT_INCREMENT;
		break;
		case GO_UP:
				this->cameraPosition.xyz[SG_Z]   += CAMERA_ELEV_INCREMENT;
		break;
		case GO_DOWN:
				this->cameraPosition.xyz[SG_Z]   -= CAMERA_ELEV_INCREMENT;
		break;
		case GO_AHEAD:
				this->cameraPosition.xyz[SG_X] += 0.1f * CAMERA_SPEED * -(float)sin(cameraPosition.hpr[HEADING] * SG_DEGREES_TO_RADIANS) * (float)cos(cameraPosition.hpr[PITCH] * SG_DEGREES_TO_RADIANS); 
				this->cameraPosition.xyz[SG_Y] += 0.1f * CAMERA_SPEED * (float)cos(cameraPosition.hpr[HEADING] * SG_DEGREES_TO_RADIANS) * (float)cos(cameraPosition.hpr[PITCH] * SG_DEGREES_TO_RADIANS); 
				this->cameraPosition.xyz[SG_Z] += 0.1f * CAMERA_SPEED * (float)sin(cameraPosition.hpr[PITCH]  * SG_DEGREES_TO_RADIANS);//0;//cameraPosition.speed ;//* (float)cos(cameraPosition.position.hpr[PITCH] * SG_DEGREES_TO_RADIANS) ; 
		break;
		case GO_BACKWARDS:
				this->cameraPosition.xyz[SG_X] -= 0.1f * CAMERA_SPEED * -(float)sin(cameraPosition.hpr[HEADING] * SG_DEGREES_TO_RADIANS) * (float)cos(cameraPosition.hpr[PITCH] * SG_DEGREES_TO_RADIANS); 
				this->cameraPosition.xyz[SG_Y] -= 0.1f * CAMERA_SPEED * (float)cos(cameraPosition.hpr[HEADING] * SG_DEGREES_TO_RADIANS) * (float)cos(cameraPosition.hpr[PITCH] * SG_DEGREES_TO_RADIANS); 
				this->cameraPosition.xyz[SG_Z] -= 0.1f * CAMERA_SPEED * (float)sin(cameraPosition.hpr[PITCH]  * SG_DEGREES_TO_RADIANS);//0;//cameraPosition.speed ;//* (float)cos(cameraPosition.position.hpr[PITCH] * SG_DEGREES_TO_RADIANS) ; 
		break;
		case RESET:
				this->cameraDistance = CAMERA_DISTANCE_RADIUS;
				this->cameraPosition.xyz[SG_X]		= 0.0f ;
				this->cameraPosition.xyz[SG_Y]		= 0.0f;
				this->cameraPosition.xyz[SG_Z]		= CAMERA_DISTANCE_RADIUS ;
				this->cameraPosition.hpr[HEADING]   = 0.0;
				this->cameraPosition.hpr[PITCH]     = -90.0;
				this->cameraPosition.hpr[ROLL]      = 0.0;
		break;
		case STRIFE_LEFT:
				this->cameraPosition.xyz[SG_X] += 0.1f * CAMERA_SPEED * -(float)sin((cameraPosition.hpr[HEADING] - STRIFE_ANGLE) * SG_DEGREES_TO_RADIANS) * (float)cos(cameraPosition.hpr[ROLL] * SG_DEGREES_TO_RADIANS); 
				this->cameraPosition.xyz[SG_Y] += 0.1f * CAMERA_SPEED * (float)cos((cameraPosition.hpr[HEADING] - STRIFE_ANGLE) * SG_DEGREES_TO_RADIANS) * (float)cos(cameraPosition.hpr[ROLL] * SG_DEGREES_TO_RADIANS); 
				this->cameraPosition.xyz[SG_Z] += 0.1f * CAMERA_SPEED * (float)sin(cameraPosition.hpr[ROLL]  * SG_DEGREES_TO_RADIANS);//0;//cameraPosition.speed ;//* (float)cos(cameraPosition.position.hpr[PITCH] * SG_DEGREES_TO_RADIANS) ; 				
		break;
		case STRIFE_RIGHT:
				this->cameraPosition.xyz[SG_X] += 0.1f * CAMERA_SPEED * -(float)sin((cameraPosition.hpr[HEADING] + STRIFE_ANGLE) * SG_DEGREES_TO_RADIANS) * (float)cos(cameraPosition.hpr[ROLL] * SG_DEGREES_TO_RADIANS); 
				this->cameraPosition.xyz[SG_Y] += 0.1f * CAMERA_SPEED * (float)cos((cameraPosition.hpr[HEADING] + STRIFE_ANGLE) * SG_DEGREES_TO_RADIANS) * (float)cos(cameraPosition.hpr[ROLL] * SG_DEGREES_TO_RADIANS); 
				this->cameraPosition.xyz[SG_Z] += 0.1f * CAMERA_SPEED * (float)sin(cameraPosition.hpr[ROLL]  * SG_DEGREES_TO_RADIANS);//0;//cameraPosition.speed ;//* (float)cos(cameraPosition.position.hpr[PITCH] * SG_DEGREES_TO_RADIANS) ; 				
		break;
		default:
		break;
		}

if(cameraPosition.xyz[SG_Z] < (hot + MIN_HOT)) 	cameraPosition.xyz[SG_Z] = (hot + MIN_HOT);

if(cameraPosition.hpr[0] >= 360.0f) cameraPosition.hpr[0] -= 360.0f;
else if(cameraPosition.hpr[0] <= -360.0f) cameraPosition.hpr[0] += 360.0f;

if(cameraPosition.hpr[1] >= 360.0f) cameraPosition.hpr[1] -= 360.0f;
else if(cameraPosition.hpr[1] <= -360.0f) cameraPosition.hpr[1] += 360.0f;

if(cameraPosition.hpr[2] >= 360.0f) cameraPosition.hpr[2] -= 360.0f;
else if(cameraPosition.hpr[2] <= -360.0f) cameraPosition.hpr[2] += 360.0f;

ssgSetCamera(&cameraPosition);
}

void Camera::movieMove(int mov, float hot)
{
//printf("Moving movie\n");
switch(mov)
		{
		case TURN_LEFT:
				this->moviePosition.hpr[HEADING]  += CAMERA_ROT_INCREMENT;
		break;
		case TURN_RIGHT:
				this->moviePosition.hpr[HEADING]  -= CAMERA_ROT_INCREMENT;
		break;
		case LOOK_UP:
				this->moviePosition.hpr[PITCH]  += CAMERA_ROT_INCREMENT;
		break;
		case LOOK_DOWN:
				this->moviePosition.hpr[PITCH]  -= CAMERA_ROT_INCREMENT;
		break;
		case GO_UP:
				this->moviePosition.xyz[SG_Z]   += CAMERA_ELEV_INCREMENT;
		break;
		case GO_DOWN:
				this->moviePosition.xyz[SG_Z]   -= CAMERA_ELEV_INCREMENT;
		break;
		case GO_AHEAD:
				this->moviePosition.xyz[SG_X] += 0.1f * CAMERA_SPEED * -(float)sin(moviePosition.hpr[HEADING] * SG_DEGREES_TO_RADIANS) * (float)cos(moviePosition.hpr[PITCH] * SG_DEGREES_TO_RADIANS); 
				this->moviePosition.xyz[SG_Y] += 0.1f * CAMERA_SPEED * (float)cos(moviePosition.hpr[HEADING] * SG_DEGREES_TO_RADIANS) * (float)cos(moviePosition.hpr[PITCH] * SG_DEGREES_TO_RADIANS); 
				this->moviePosition.xyz[SG_Z] += 0.1f * CAMERA_SPEED * (float)sin(moviePosition.hpr[PITCH]  * SG_DEGREES_TO_RADIANS);//0;//moviePosition.speed ;//* (float)cos(moviePosition.position.hpr[PITCH] * SG_DEGREES_TO_RADIANS) ; 
		break;
		case GO_BACKWARDS:
				this->moviePosition.xyz[SG_X] -= 0.1f * CAMERA_SPEED * -(float)sin(moviePosition.hpr[HEADING] * SG_DEGREES_TO_RADIANS) * (float)cos(moviePosition.hpr[PITCH] * SG_DEGREES_TO_RADIANS); 
				this->moviePosition.xyz[SG_Y] -= 0.1f * CAMERA_SPEED * (float)cos(moviePosition.hpr[HEADING] * SG_DEGREES_TO_RADIANS) * (float)cos(moviePosition.hpr[PITCH] * SG_DEGREES_TO_RADIANS); 
				this->moviePosition.xyz[SG_Z] -= 0.1f * CAMERA_SPEED * (float)sin(moviePosition.hpr[PITCH]  * SG_DEGREES_TO_RADIANS);//0;//moviePosition.speed ;//* (float)cos(moviePosition.position.hpr[PITCH] * SG_DEGREES_TO_RADIANS) ; 
		break;
		case RESET:
		break;
		case STRIFE_LEFT:
				this->moviePosition.xyz[SG_X] += 0.1f * CAMERA_SPEED * -(float)sin((moviePosition.hpr[HEADING] - STRIFE_ANGLE) * SG_DEGREES_TO_RADIANS) * (float)cos(moviePosition.hpr[ROLL] * SG_DEGREES_TO_RADIANS); 
				this->moviePosition.xyz[SG_Y] += 0.1f * CAMERA_SPEED * (float)cos((moviePosition.hpr[HEADING] - STRIFE_ANGLE) * SG_DEGREES_TO_RADIANS) * (float)cos(moviePosition.hpr[ROLL] * SG_DEGREES_TO_RADIANS); 
				this->moviePosition.xyz[SG_Z] += 0.1f * CAMERA_SPEED * (float)sin(moviePosition.hpr[ROLL]  * SG_DEGREES_TO_RADIANS);//0;//moviePosition.speed ;//* (float)cos(moviePosition.position.hpr[PITCH] * SG_DEGREES_TO_RADIANS) ; 				
		break;
		case STRIFE_RIGHT:
				this->moviePosition.xyz[SG_X] += 0.1f * CAMERA_SPEED * -(float)sin((moviePosition.hpr[HEADING] + STRIFE_ANGLE) * SG_DEGREES_TO_RADIANS) * (float)cos(moviePosition.hpr[ROLL] * SG_DEGREES_TO_RADIANS); 
				this->moviePosition.xyz[SG_Y] += 0.1f * CAMERA_SPEED * (float)cos((moviePosition.hpr[HEADING] + STRIFE_ANGLE) * SG_DEGREES_TO_RADIANS) * (float)cos(moviePosition.hpr[ROLL] * SG_DEGREES_TO_RADIANS); 
				this->moviePosition.xyz[SG_Z] += 0.1f * CAMERA_SPEED * (float)sin(moviePosition.hpr[ROLL]  * SG_DEGREES_TO_RADIANS);//0;//moviePosition.speed ;//* (float)cos(moviePosition.position.hpr[PITCH] * SG_DEGREES_TO_RADIANS) ; 				
		break;
		default:
		break;
		}

if(moviePosition.xyz[SG_Z] < (hot + MIN_HOT)) moviePosition.xyz[SG_Z] = (hot + MIN_HOT);

if(moviePosition.hpr[0] >= 360.0f) moviePosition.hpr[0] -= 360.0f;
else if(moviePosition.hpr[0] <= -360.0f) moviePosition.hpr[0] += 360.0f;

if(moviePosition.hpr[1] >= 360.0f) moviePosition.hpr[1] -= 360.0f;
else if(moviePosition.hpr[1] <= -360.0f) moviePosition.hpr[1] += 360.0f;

if(moviePosition.hpr[2] >= 360.0f) moviePosition.hpr[2] -= 360.0f;
else if(moviePosition.hpr[2] <= -360.0f) moviePosition.hpr[2] += 360.0f;

ssgSetCamera(&moviePosition);
}

float Camera::getRadius()
{
return this->cameraDistance;
}

void Camera::switchToEditingView()
{
inner_state = FREE_MOVE;
ssgSetCamera(&cameraPosition);
}

void Camera::switchToCameraRepositioningView()
{
inner_state = MOVIE_MOVE;
ssgSetCamera(&moviePosition);
}

void Camera::switchToMovieView()
{
inner_state = VIEW_MOVIE;
}